
#include <ctype.h>
#include <memory.h>
#include "ISO8583_inc.h"
#include "ByteUtil.h"

namespace suxw
{
    unsigned char ByteUtil::m_buf[ByteUtil::MAX_SIZE];

    //convert 2 ascii char to bcd char
    //pcAsc is address of charater buffer, the char is digit or belong to ['a', 'f']
    unsigned char ByteUtil::asc2Bcd(const char *pcAsc)
    {
        char val[2];
        unsigned char bcd = 0;

        memcpy(val, pcAsc, 2);
        if (isdigit(val[0]))
        {
            val[0] -= '0';
        }
        else
        {
            val[0] -= 'a';
        }
        if (isdigit(val[1]))
        {
            val[1] -= '0';
        }
        else
        {
            val[1] -= 'a';
        }
        bcd = (val[0] << 4) | (val[1] & 0x0f);

        return bcd;
    }

    //convert ascii string to bcd data buffer
    //nLen - length of ascii string
    bool ByteUtil::convertAsc2Bcd(unsigned char* pcBcd, const char *pcAsc, int nLen, AlignType alignType, char cPadChar)
    {
        if (!isValidChar(cPadChar))
        {
            return false;
        }
        if ((nLen <= 0) || (nLen > MAX_SIZE))
        {
            return false;
        }
        
        memset(m_buf, 0, MAX_SIZE);
        if (nLen % 2)
        {
            if (alignType == LEFT)
            {
                memcpy(m_buf, pcAsc, nLen);
                m_buf[nLen] = cPadChar;
            }
            else
            {
                m_buf[0] = cPadChar;
                memcpy(m_buf + 1, pcAsc, nLen);
            }
            ++nLen;
        }
        else
        {
            memcpy(m_buf, pcAsc, nLen);
        }

        unsigned char bcd = 0;
        for (int i = 0; i < (nLen / 2); i++)
        {
            pcBcd[i] = asc2Bcd(pcAsc + (i * 2));
        }
        
        return true;
    }

    //convert bcd data buffer to ascii string
    //nLen - count of ascii characters
    bool ByteUtil::convertBcd2Asc(const unsigned char* pcBcd, char *pcAsc, int nLen, AlignType alignType)
    {
        char cvtTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        int i = 0;
        int nCur = 0;

        if (nLen % 2)
        {
            ++nLen;
            if (alignType == RIGHT)
            {
                pcAsc[nCur++] = cvtTable[pcBcd[i++] & 0x0f];
            }
        }

        for (; i < (nLen / 2); i++)
        {
            pcAsc[nCur++] = cvtTable[(pcBcd[i] >> 4) & 0x0f];
            pcAsc[nCur++] = cvtTable[pcBcd[i] & 0x0f];
        }
        pcAsc[nCur] = 0;

        return true;
    }

    //judge is valid char
    bool ByteUtil::isValidChar(char c)
    {
        if (isdigit(c))
        {
            return true;
        }
        int tmp = tolower(c);
        if ((tmp >= 'a') && (tmp <= 'f'))
        {
            return true;
        }
        
        return false;
    }
}
